package org.study.concurrent;

import lombok.Data;
import sun.misc.Unsafe;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.concurrent.atomic.*;
import java.util.function.DoubleBinaryOperator;
import java.util.function.LongBinaryOperator;

/**
 * 类的描述
 *
 * @author Administrator
 * @date 2022-11-30
 */
public class AtomicTests {
    static Unsafe unsafe;

    static {
        try {
            // 不能通过 Unsafe.getUnsafe() 获取到 Unsafe 对象，可以通过反射来获取
            // Unsafe unsafe = Unsafe.getUnsafe();
            // 参考 https://blog.csdn.net/qq_43605444/article/details/121570839
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        System.out.println("==================== testUnsafe()");
        testUnsafe();

        System.out.println("==================== testAtomicIntegerFieldUpdater()");
        testAtomicIntegerFieldUpdater();

        System.out.println("==================== testAtomicIntegerArray()");
        testAtomicIntegerArray();

        System.out.println("==================== testLongAdder()");
        testLongAdder();

        System.out.println("==================== testLongAccumulator()");
        testLongAccumulator();

        System.out.println("==================== testDoubleAdder()");
        testDoubleAdder();

        System.out.println("==================== testDoubleAccumulator()");
        testDoubleAccumulator();
    }

    public static void testUnsafe() {
        // arrayBaseOffset() 获取数组的首地址的位置
        // arrayIndexScale() 获取一个数组元素的大小
        System.out.println("booleanBaseOffset=" + unsafe.arrayBaseOffset(boolean[].class));
        System.out.println("booleanIndexScale=" + unsafe.arrayIndexScale(boolean[].class));
        System.out.println("byteBaseOffset=" + unsafe.arrayBaseOffset(byte[].class));
        System.out.println("byteIndexScale=" + unsafe.arrayIndexScale(byte[].class));
        System.out.println("intBaseOffset=" + unsafe.arrayBaseOffset(int[].class));
        System.out.println("intIndexScale=" + unsafe.arrayIndexScale(int[].class));
        System.out.println("longBaseOffset=" + unsafe.arrayBaseOffset(long[].class));
        System.out.println("longIndexScale=" + unsafe.arrayIndexScale(long[].class));
        System.out.println("doubleBaseOffset=" + unsafe.arrayBaseOffset(double[].class));
        System.out.println("doubleIndexScale=" + unsafe.arrayIndexScale(double[].class));
        System.out.println("stringBaseOffset=" + unsafe.arrayBaseOffset(String[].class));
        System.out.println("stringIndexScale=" + unsafe.arrayIndexScale(String[].class));
    }

    public static void testAtomicIntegerFieldUpdater() {
        User user = new User();
        user.setUserId(1L);
        user.setAge(18);

        // 使用 AtomicIntegerFieldUpdater 修改成员变量时，要求成员变量必须是 volatile 的 int 类型
        AtomicIntegerFieldUpdater<User> userFieldUpdater = AtomicIntegerFieldUpdater.newUpdater(User.class, "age");
        int age1 = userFieldUpdater.getAndIncrement(user);
        System.out.println(age1);

        int age2 = userFieldUpdater.get(user);
        System.out.println(age2);

        if (userFieldUpdater.compareAndSet(user, 18, 30)) {
            System.out.println("修改成功之后的值：" + userFieldUpdater.get(user));
        } else {
            System.out.println("修改失败之后的值：" + userFieldUpdater.get(user));
        }
    }

    public static void testAtomicIntegerArray() {
        int[] intArray = new int[]{1, 2, 3, 4, 5};

        // 对数租的原子操作，注意不是针对整个数组的操作是原子的，而是针对数组中的某个元素的操作是原子的
        AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(intArray);

        int index1 = atomicIntegerArray.getAndIncrement(0);
        System.out.println(index1);

        int index2 = atomicIntegerArray.get(0);
        System.out.println(index2);

        if (atomicIntegerArray.compareAndSet(1, 2, 20)) {
            System.out.println("修改成功之后的值：" + atomicIntegerArray.get(1));
        } else {
            System.out.println("修改失败之后的值：" + atomicIntegerArray.get(1));
        }
    }

    public static void testLongAdder() {
        // LongAdder 只能进行累加操作，且初始值默认是0
        LongAdder longAdder = new LongAdder();
        System.out.println("初始值：" + longAdder.longValue());

        longAdder.increment();
        System.out.println("自增后：" + longAdder.longValue());

        longAdder.add(10);
        System.out.println("加10后：" + longAdder.longValue());

        System.out.println("sum()后：" + longAdder.sum());

        longAdder.reset();
        System.out.println("reset()后：" + longAdder.longValue());

        long sumThenReset = longAdder.sumThenReset();
        System.out.println("sumThenReset()后：" + sumThenReset);
    }

    public static void testLongAccumulator() {
        // LongAccumulator 可以自定义一个二元操作符，并且可以传入一个指定的初始值
        LongAccumulator longAccumulator = new LongAccumulator(new LongBinaryOperator() {
            /**
             * 方法功能描述
             * @param left 操作符的左值：base 变量或 Cells[] 中元素的当前值
             * @param right 操作符的右值：accumulate() 函数传入的参数 x
             * @return long
             */
            @Override
            public long applyAsLong(long left, long right) {
                return left + right;
            }
        }, 1);
        System.out.println("初始值：" + longAccumulator.get());

        // LongAccumulator 中的 accumulate(x) 与 LongAdder 中的 add(x) 类似
        longAccumulator.accumulate(10);
        System.out.println("加10后：" + longAccumulator.get());

        longAccumulator.reset();
        System.out.println("reset()后：" + longAccumulator.get());

        long getThenReset = longAccumulator.getThenReset();
        System.out.println("getThenReset()后：" + getThenReset);
    }

    public static void testDoubleAdder() {
        DoubleAdder doubleAdder = new DoubleAdder();
        System.out.println("初始值：" + doubleAdder.doubleValue());

        doubleAdder.add(10);
        System.out.println("加10后：" + doubleAdder.doubleValue());

        System.out.println("sum()后：" + doubleAdder.sum());

        doubleAdder.reset();
        System.out.println("reset()后：" + doubleAdder.doubleValue());

        double sumThenReset = doubleAdder.sumThenReset();
        System.out.println("sumThenReset()后：" + sumThenReset);
    }

    public static void testDoubleAccumulator() {
        DoubleAccumulator doubleAccumulator = new DoubleAccumulator(new DoubleBinaryOperator() {
            /**
             * 方法功能描述
             * @param left 操作符的左值：base 变量或 Cells[] 中元素的当前值
             * @param right 操作符的右值：accumulate() 函数传入的参数 x
             * @return long
             */
            @Override
            public double applyAsDouble(double left, double right) {
                return left + right;
            }
        }, 10.06);
        System.out.println("初始值：" + doubleAccumulator.get());

        // DoubleAccumulator 中的 accumulate(x) 与 DoubleAdder 中的 add(x) 类似
        doubleAccumulator.accumulate(3.01);
        System.out.println("加3.01后：" + doubleAccumulator.get());

        doubleAccumulator.reset();
        System.out.println("reset()后：" + doubleAccumulator.get());

        double getThenReset = doubleAccumulator.getThenReset();
        System.out.println("getThenReset()后：" + getThenReset);
    }

    @Data
    static class User implements Serializable {
        public volatile long userId;
        public volatile int age;
    }
}
